package com.henghe.frame.ddl.util.dm;


import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.henghe.frame.ddl.constant.DdlConstant;
import com.henghe.frame.ddl.pojo.ColumnVo;
import com.henghe.frame.ddl.pojo.TableColumnEntity;
import com.henghe.frame.ddl.pojo.dm.DmTableEntity;
import com.henghe.frame.ddl.util.DbUtil;
import com.henghe.frame.common.util.CamelUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * Description:
 * Author: LiuWenQing
 * Datetime: 2023/9/19 14:01
 */
@Slf4j
public class DmDdlUtil extends DbUtil {

    public static List<Class> generatorClasses = Arrays.asList(int.class,
            Integer.class, String.class, Long.class, long.class, BigDecimal.class, Date.class, LocalDateTime.class);


    public static List<DmTableEntity> getCodeDb(String path, String schema) {
        return searchPackageEntities(path, schema);
    }


    /**
     * 找到指定包下所有带注解的实体类
     *
     * @param packagePath
     * @return
     */
    private static List<DmTableEntity> searchPackageEntities(String packagePath, String schema) {
        if (StringUtils.isEmpty(schema))
            return null;

        Reflections reflections = new Reflections(packagePath);
        Set<Class<?>> typesAnnotated = reflections.getTypesAnnotatedWith(TableName.class);

        List<DmTableEntity> dmTableEntities = new ArrayList<>();
        for (Class<?> aClass : typesAnnotated) {
            DmTableEntity dmTableEntity = new DmTableEntity();
            TableName table = (TableName) aClass.getAnnotation(TableName.class);
            if (table == null || StringUtils.isEmpty(table.value()))
                continue;

            List<Field> fields = Arrays.asList(aClass.getDeclaredFields());
            long count = fields.stream().filter(e -> e.getAnnotation(TableId.class) != null).count();
            if (count > 1)
                continue;
            Boolean hasId = fields.stream().filter(e -> e.getAnnotation(TableId.class) != null
                    && generatorClasses.contains(e.getType())).findAny().isPresent();
            if (!hasId)
                continue;
            dmTableEntity.setDefaultCharset("utf8");
            dmTableEntity.setTableName(table.value());
            dmTableEntity.setSchema(schema);
            List<TableColumnEntity> columns = new ArrayList<>();
            for (Field field : fields) {
                if (!generatorClasses.contains(field.getType()))
                    continue;
                TableField tableFieldAno = field.getAnnotation(TableField.class);
                if (tableFieldAno != null && tableFieldAno.exist() == false)
                    continue;

                TableColumnEntity column = new TableColumnEntity();
                TableId tableIdAno = field.getAnnotation(TableId.class);
                if (tableIdAno != null) {
                    // id
                    column.setName(StringUtils.isNotEmpty(tableIdAno.value()) ? tableIdAno.value() : "id");
                    column.setComment(DdlConstant.idComment);
                    column.setIsPrimaryKey(true);
                    column.setIsNotNull(Boolean.TRUE);
                    if (tableIdAno.type() == null) {
                        column.setType("bigint");
                    } else {
                        switch (tableIdAno.type()) {
                            case NONE:
                                column.setType("bigint");
                                break;
                            case AUTO:
                                column.setType("bigint");
                                column.setGenerateType("identity(1,1)");
                                column.setAutoIncrement(1);
                                break;
                            case INPUT:
                                if (field.getType().equals(String.class)) {
                                    column.setType("varchar");
                                    column.setLength("32");
                                } else if (field.getType().equals(int.class) ||
                                        field.getType().equals(Integer.class)) {
                                    column.setType("bigint");
                                } else {
                                }
                                break;
                            case ASSIGN_ID:
                                column.setType("bigint");
                                break;
                            case ASSIGN_UUID:
                                column.setType("varchar");
                                column.setLength("32");
                                break;
                            default: {
                            }
                        }
                    }
                    columns.add(column);
                    continue;
                }

                column.setName(CamelUtil.camelToUnderline(field.getName()));
                if (field.getType().equals(String.class)) {
                    column.setType("varchar2");
                    column.setLength("255");
                } else if (field.getType().equals(Integer.class) ||
                        field.getType().equals(int.class)) {
                    column.setType("integer");
                    column.setLength("11");
                } else if (field.getType().equals(Long.class) ||
                        field.getType().equals(long.class)) {
                    column.setType("bigint");
                } else if (field.getType().equals(BigDecimal.class)) {
                    column.setType("NUMBER");
                    column.setLength("10,2");
                }
                column.setIsNotNull(Boolean.FALSE);
                column.setIsPrimaryKey(false);
                columns.add(column);
            }
            dmTableEntity.setColumns(columns);
            dmTableEntities.add(dmTableEntity);
        }
        return dmTableEntities;
    }

    public static String addColumn(TableColumnEntity tableColumnEntity, String tableName, String schema) {
        String sql = "alter table \"" + schema + "\".\"" + tableName + "\" add column(" + tableColumnEntity.getName();
        if (tableColumnEntity.getType().equals("varchar2")) {
            sql += " " + tableColumnEntity.getType() + "(" + tableColumnEntity.getLength() + "))";
        } else {
            sql += " " + tableColumnEntity.getType() + ")";
        }
        return sql;
    }

    public static String updateColumn(TableColumnEntity tableColumnEntity, String tableName, String schema) {
        String sql = "alter table \"" + schema + "\".\"" + tableName + "\" MODIFY " + tableColumnEntity.getName();
        if (tableColumnEntity.getType().equals("varchar2")) {
            sql += " " + tableColumnEntity.getType() + "(" + tableColumnEntity.getLength() + ")";
        } else {
            sql += " " + tableColumnEntity.getType();
        }
        return sql;
    }

    public static Boolean typeEquals(TableColumnEntity tableColumnEntity, ColumnVo columnVo) {
        if (tableColumnEntity.getType().equals("varchar2") &&
                !(DdlConstant.DmStrTypes.contains(columnVo.getDataType().trim()))) {
            return false;
        }

        if (tableColumnEntity.getType().equals("integer") &&
                !columnVo.getDataType().equals("INTEGER")) {
            return false;
        }

        if (tableColumnEntity.getType().equals("bigint") &&
                !columnVo.getDataType().equals("BIGINT")) {
            return false;
        }

        //ToDo 浮点数判断

        return true;
    }


    public static List<String> generateTables(List<DmTableEntity> dmTableEntities) {
        List<String> sqls = new ArrayList<>();
        for (DmTableEntity dmTableEntity : dmTableEntities) {
            sqls.add(generateTables(dmTableEntity));
        }
        return sqls;
    }

    public static String generateTables(DmTableEntity dmTableEntity) {
        StringBuffer stringBuffer = new StringBuffer("");
        stringBuffer.append("CREATE TABLE IF NOT EXISTS \"" + dmTableEntity.getSchema() + "\".\"" + dmTableEntity.getTableName() + "\" (");
        List<TableColumnEntity> columns = dmTableEntity.getColumns();
        TableColumnEntity idColumn = columns.stream().filter(e -> e.getIsPrimaryKey() == true).findAny().orElse(null);
        for (TableColumnEntity column : columns) {
            stringBuffer.append("\"" + column.getName() + "\" " + column.getType());
            if (StringUtils.isNotEmpty(column.getLength()))
                stringBuffer.append("(" + column.getLength() + ")");
            if (StringUtils.isNotEmpty(column.getGenerateType()))
                stringBuffer.append(" " + column.getGenerateType());
            if (column.getIsNotNull())
                stringBuffer.append(" NOT NULL");
            stringBuffer.append(",");
        }
        stringBuffer.append("PRIMARY KEY (\"" + idColumn.getName() + "\")) ");
        return stringBuffer.toString();
    }

}
